# -*- coding: utf-8 -*-
"""
Module Description: 调用适配前端
"""
import json

import requests

from common.service_config import DalMode
from framework.core.context import get_trace_id

from framework.dal.orm.orm_expection import ORMException


def exception_handle(func):
    """捕获所有http请求异常"""
    def _exc(*args, **kwargs):
        try:
            res = func(*args, **kwargs)
            if DalMode.is_peewee_mode() or DalMode.is_sqlite_mode():
                return res

            if res['code'] == 10000:
                return json.loads(res['info'])
            assert res['code'] == 10000, ORMException("code: %d\ninfo: %s" % (res['code'], res['info']))
        except requests.ConnectionError as e:
            return print_retry(func, 2, *args, **kwargs)
    return _exc


def print_retry(f, retry_count, *args, **kwargs):
    retry_run_count = 0
    for i in range(retry_count):
        try:
            res = f(*args, **kwargs)
            if res['code'] == 10000:
                return json.loads(res['info'])
            else:
                # 跳过异常重试判断,丢出异常
                retry_run_count = retry_count
                raise ORMException("code: %d\ninfo: %s" % (res['code'], res['info']))
        except Exception as e:
            if retry_run_count < retry_count - 1:
                retry_run_count += 1
                continue
            else:
                raise e


def return_method():
    from framework.dal.orm.remote_call import chaos_api
    from framework.dal.orm.remote_call import peewee_api

    if DalMode.is_chaos_mode():
        return chaos_api
    elif DalMode.is_peewee_mode():
        return peewee_api
    elif DalMode.is_sqlite_mode():
        return peewee_api

    raise NotImplementedError


def ref_mth(func_name):
    """返回正确的实现方法"""
    method = return_method()
    if method is None:
        raise ORMException("None method")
    f = getattr(method, func_name)
    if not callable(f):
        raise ORMException("method not be used")
    return f


@exception_handle
def insert_model(db_name, mdl_cls, values):
    func = ref_mth("insert_model")
    return func(db_name, mdl_cls, values, get_trace_id())


@exception_handle
def delete_model(db_name, mdl_cls, conditions, operator="AND"):
    func = ref_mth("delete_model")
    return func(db_name, mdl_cls, conditions, operator, get_trace_id())


@exception_handle
def update_model(db_name, model_name, pks, values, conditions, operator="AND"):
    func = ref_mth("update_model")
    return func(db_name, model_name, pks, values, conditions, operator, get_trace_id())


@exception_handle
def select_model(db_name, model_name, pks, conditions, columns=None,
                 operator="AND", order=None, limit=None, offset=0):
    func = ref_mth("select_model")
    return func(db_name, model_name, pks, conditions, columns,
                operator, order, limit, offset, get_trace_id())


@exception_handle
def select_count(db_name, mdl_cls, conditions):
    func = ref_mth("select_count")
    return func(db_name, mdl_cls, conditions, get_trace_id())


@exception_handle
def select_min(db_name, mdl_cls, field_name, conditions):
    func = ref_mth("select_min")
    return func(db_name, mdl_cls, field_name, conditions, get_trace_id())


@exception_handle
def select_max(db_name, mdl_cls, field_name,conditions):
    func = ref_mth("select_max")
    return func(db_name, mdl_cls, field_name, conditions, get_trace_id())


@exception_handle
def transaction_model(trans_obj, work):
    func = ref_mth("transaction_model")
    return func(trans_obj, work, get_trace_id())


@exception_handle
def query_sql(db_name, sql):
    func = ref_mth("query_sql")
    return func(db_name, sql, get_trace_id())
